﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using Geometric;

//注意：屏幕 笛卡尔坐标系，原点在左下角

namespace LaserMark
{
    class RotateRectangle
    {
        public double width;
        public double height;
        public double center_x;
        public double center_y;
        public double[,] points;
        public bool isValid;
        public bool isSelected = false;
        public double angle;
        public string element_id;
        public double z_pos;

        public RotateRectangle Clone()
        {
            RotateRectangle result = new RotateRectangle();
            result.width = this.width;
            result.height = this.height;
            result.center_x = this.center_x;
            result.center_y = this.center_y;
            result.isValid = this.isValid;
            result.isSelected = this.isSelected;
            result.element_id = this.element_id;
            result.angle = this.angle;

            for (int i = 0; i < 4; i++)
            {
                result.points[i, 0] = this.points[i, 0];
                result.points[i, 1] = this.points[i, 1];
            }
            return result;
        }

        public RotateRectangle()
        {
            points = new double[4, 2];
            isValid = false;
        }

        public RotateRectangle(double x, double y, double width, double height, string elementId)
        {
            isValid = true;
            this.center_x = x + width / 2.0;
            this.center_y = y - height / 2.0;
            this.width = width;
            this.height = height;

            double half_w = this.width / 2.0;
            double half_h = this.height / 2.0;
            points = new double[4, 2];
            points[0, 0] = this.center_x - half_w;
            points[0, 1] = this.center_y + half_h;

            points[1, 0] = this.center_x + half_w;
            points[1, 1] = this.center_y + half_h;

            points[2, 0] = this.center_x + half_w;
            points[2, 1] = this.center_y - half_h;

            points[3, 0] = this.center_x - half_w;
            points[3, 1] = this.center_y - half_h;

            angle = 0;

            this.element_id = elementId;

            z_pos = 0;
        }
        public void setZPos(double z_pos_v)
        {
            this.z_pos = z_pos_v;
        }
        public void getDirectionTrianglePoints(ref double[,] trianglePoints)
        {

            double w_4 = this.width / 8.0;
            double h_4 = this.height / 4.0;
            double h_2 = this.height / 2.0;

            double target_angle = (this.angle * NOCConstant.Pi) / 180.0;
            NOCVector2D axis_x = new NOCVector2D(1, 0);
            axis_x.rotate(target_angle);
            NOCVector2D axis_y = axis_x.rotated(NOCConstant.Pi / 2.0);
            axis_y.normalize();

            NOCVector2D pc = new NOCVector2D(this.center_x, this.center_y);

            NOCVector2D _h_4_move = axis_y.muledConstant(-h_4);
            NOCVector2D p1 = pc.addedVector(ref _h_4_move);
            trianglePoints[0, 0] = p1.x;
            trianglePoints[0, 1] = p1.y;

            NOCVector2D _h_2_move = axis_y.muledConstant(-h_2);
            NOCVector2D _w_4_move = axis_x.muledConstant(-w_4);
            NOCVector2D p2 = pc.addedVector(ref _h_2_move).addedVector(ref _w_4_move);
            trianglePoints[1, 0] = p2.x;
            trianglePoints[1, 1] = p2.y;

            NOCVector2D w_4_move = axis_x.muledConstant(w_4);
            NOCVector2D p3 = pc.addedVector(ref _h_2_move).addedVector(ref w_4_move);
            trianglePoints[2, 0] = p3.x;
            trianglePoints[2, 1] = p3.y;
        }

        public void getDragCircles(ref double[,] centers, ref double[] radius)
        {
            double w_2 = this.width / 2.0;
            double h_2 = this.height / 2.0;

            double r = Math.Min(this.width, this.height) / 8.0;

            double target_angle = (this.angle * NOCConstant.Pi) / 180.0;
            NOCVector2D axis_x = new NOCVector2D(1, 0);
            axis_x.rotate(target_angle);
            NOCVector2D axis_y = axis_x.rotated(NOCConstant.Pi / 2.0);
            axis_y.normalize();

            NOCVector2D pc = new NOCVector2D(this.center_x, this.center_y);

            NOCVector2D w_2_move = axis_x.muledConstant(w_2);
            NOCVector2D p1 = pc.addedVector(ref w_2_move);
            centers[0, 0] = p1.x;
            centers[0, 1] = p1.y;
            radius[0] = r;

            NOCVector2D h_2_move = axis_y.muledConstant(h_2);
            NOCVector2D p2 = pc.addedVector(ref h_2_move);
            centers[1, 0] = p2.x;
            centers[1, 1] = p2.y;
            radius[1] = r;

            NOCVector2D _h_2_move = axis_y.muledConstant(-h_2);
            NOCVector2D p3 = pc.addedVector(ref _h_2_move);
            centers[2, 0] = p3.x;
            centers[2, 1] = p3.y;
            radius[2] = r/1.5;

            centers[3, 0] = pc.x;
            centers[3, 1] = pc.y;
            radius[3] = r / 1.2;
        }

        private void recalcCornerCoor()
        {
            double half_w = this.width / 2.0;
            double half_h = this.height / 2.0;
            double angle = this.angle;

            double target_angle = (angle * NOCConstant.Pi) / 180.0;
            NOCVector2D axis_x = new NOCVector2D(1, 0);
            axis_x.normalize();

            axis_x.rotate(target_angle);

            NOCVector2D axis_y = axis_x.rotated(NOCConstant.Pi / 2.0);

            NOCVector2D center = new NOCVector2D(this.center_x, this.center_y);

            NOCVector2D x_half_move = axis_x.muledConstant(half_w);
            NOCVector2D y_half_move = axis_y.muledConstant(half_h);
            center.addVector(ref x_half_move);
            center.addVector(ref y_half_move);
            points[1, 0] = center.x;
            points[1, 1] = center.y;

            NOCVector2D neg_x_move = axis_x.muledConstant(-this.width);
            center.addVector(ref neg_x_move);
            points[0, 0] = center.x;
            points[0, 1] = center.y;

            NOCVector2D neg_y_move = axis_y.muledConstant(-this.height);
            center.addVector(ref neg_y_move);
            points[3, 0] = center.x;
            points[3, 1] = center.y;

            NOCVector2D x_move = axis_x.muledConstant(this.width);
            center.addVector(ref x_move);
            points[2, 0] = center.x;
            points[2, 1] = center.y;
        }

        public void rotateAngle(double angle)
        {
           
            this.angle = angle;
            recalcCornerCoor();
        }
        public double getRotateAngle()
        {
            return this.angle;
        }
        public bool isInRange(double x, double y)
        {
           
            double half_w = this.width / 2.0;
            double half_h = this.height / 2.0;

            double target_angle = (this.angle * NOCConstant.Pi) / 180.0;
            NOCVector2D axis_x = new NOCVector2D(1, 0);
            axis_x.normalize();

            axis_x.rotate(target_angle);
            NOCVector2D axis_y = axis_x.rotated(NOCConstant.Pi / 2.0);
            axis_y.normalize();

            NOCVector2D ctop = new NOCVector2D(x-this.center_x, y - this.center_y);
            double d1 = Math.Abs(axis_x.projectionOfVector(ref ctop));
            if (d1 > half_w)
            {
                return false;
            }

            double d2 = Math.Abs(axis_y.projectionOfVector(ref ctop));
            if ( d2 > half_h)
            {
                return false;
            }
            return true;
        }

        public void setCenterX(double cx)
        {
            double deltax = cx - this.center_x;
            this.center_x += deltax;
            for(int i = 0; i < 4; i++)
            {
                points[i, 0] += deltax;
            }
        }
        public void setCenterY(double cy)
        {
            double deltaY = cy - this.center_y;
            this.center_y += deltaY;
            for (int i = 0; i < 4; i++)
            {
                points[i, 1] += deltaY;
            }
        }

        public void setWidth(double width)
        {
            this.width = width;
            recalcCornerCoor();
        }

        public void setHeight(double height)
        {
            this.height = height;
            recalcCornerCoor();
        }
    }
}
